/* * Ext GWT 2.2.4 - Ext for GWT * Copyright(c) 2007-2010, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ package com.extjs.gxt.ui.client.data; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONValue; /** * A <code>DataReader</code> implementation that reads JSON data using a * <code>ModelType</code> definition and produces a set of * <code>ModelData</code> instances. * * <p /> * Subclasses can override {@link #createReturnData(Object, List, int)} to * control what object is returned by the reader. Subclass may override * {@link #newModelInstance()} to return any model data subclass. * * @param <D> the <code>ListLoadResult</code> type being returned by the reader */ @SuppressWarnings("deprecation") public class JsonReader<D> implements DataReader<D> { private ModelType modelType; /** * Creates a new JSON reader. * * @param modelType the model type definition */ public JsonReader(ModelType modelType) { this.modelType = modelType; } @SuppressWarnings({"unchecked", "rawtypes"}) public D read(Object loadConfig, Object data) { JSONObject jsonRoot = null; if (data instanceof JavaScriptObject) { jsonRoot = new JSONObject((JavaScriptObject) data); } else { jsonRoot = (JSONObject) JSONParser.parse((String) data); } JSONArray root = (JSONArray) jsonRoot.get(modelType.getRoot()); int size = root.size(); ArrayList<ModelData> models = new ArrayList<ModelData>(); for (int i = 0; i < size; i++) { JSONObject obj = (JSONObject) root.get(i); ModelData model = newModelInstance(); for (int j = 0; j < modelType.getFieldCount(); j++) { DataField field = modelType.getField(j); String name = field.getName(); Class type = field.getType(); String map = field.getMap() != null ? field.getMap() : field.getName(); JSONValue value = obj.get(map); if (value == null) continue; if (value.isArray() != null) { // nothing } else if (value.isBoolean() != null) { model.set(name, value.isBoolean().booleanValue()); } else if (value.isNumber() != null) { if (type != null) { Double d = value.isNumber().doubleValue(); if (type.equals(Integer.class)) { model.set(name, d.intValue()); } else if (type.equals(Long.class)) { model.set(name, d.longValue()); } else if (type.equals(Float.class)) { model.set(name, d.floatValue()); } else { model.set(name, d); } } else { model.set(name, value.isNumber().doubleValue()); } } else if (value.isObject() != null) { // nothing } else if (value.isString() != null) { String s = value.isString().stringValue(); if (type != null) { if (type.equals(Date.class)) { if ("timestamp".equals(field.getFormat())) { Date d = new Date(Long.parseLong(s) * 1000); model.set(name, d); } else { DateTimeFormat format = DateTimeFormat.getFormat(field.getFormat()); Date d = format.parse(s); model.set(name, d); } } } else { model.set(name, s); } } else if (value.isNull() != null) { model.set(name, null); } } models.add(model); } int totalCount = models.size(); if (modelType.getTotalName() != null) { totalCount = getTotalCount(jsonRoot); } return (D) createReturnData(loadConfig, models, totalCount); } /** * Responsible for the object being returned by the reader. * * @param loadConfig the load config * @param records the list of models * @param totalCount the total count * @return the data to be returned by the reader */ @SuppressWarnings("unchecked") protected Object createReturnData(Object loadConfig, List<ModelData> records, int totalCount) { return (D) records; } protected int getTotalCount(JSONObject root) { if (modelType.getTotalName() != null) { JSONValue v = root.get(modelType.getTotalName()); if (v != null) { if (v.isNumber() != null) { return (int) v.isNumber().doubleValue(); } else if (v.isString() != null) { return Integer.parseInt(v.isString().stringValue()); } } } return -1; } /** * Returns the new model instances. Subclasses may override to provide an * model data subclass. * * @return the new model data instance */ protected ModelData newModelInstance() { return new BaseModelData(); } }